# encoding: utf-8
""" 
@author:Daniel 
@license: Apache Licence 
@file: api_base_builder.py 
@time: 2020/07/16
@contact: tongdangdang1@yy.com
"""
import projectConfig
from .better_abc import ABCMeta, abstract_attribute
from functools import wraps


def parameter(param_order, param_type):
    def parameter_decorator(func):
        param_name = func.__name__
        func.__is_parameter__ = True

        @wraps(func)
        def wrapper(self, param_value):
            if param_type == 'boolean' or param_type == 'Boolean': # Python True/False to Java true/fasle
                param_value = str(param_value).lower()
            self.param_dict.setdefault(param_order, (param_name, param_type, param_value))
            return func(self, param_value)

        return wrapper

    return parameter_decorator


class ApiBaseBuilder(metaclass=ABCMeta):
    """ Api Base builder class for build api rpc command

    """

    @abstract_attribute
    def api_name(self):
        pass

    def __init__(self):
        self.param_dict = {}
        self.api_cmd = {}

    def build(self):
        parameter_names = {
            name
            for name in dir(self)
            if getattr(getattr(self, name), '__is_parameter__', False)
        }
        temp = [self.param_dict.get(i + 1) for i in range(len(parameter_names)) if self.param_dict.get(i + 1)]

        param = list(zip(*temp))

        miss_params = list(parameter_names.difference(set(param[0] if param else [])))
        if miss_params:
            raise Exception(
                "api [{}] has params [{}] not be called".format(
                    self.api_name,
                    ', '.join(miss_params)
                )
            )
        self.api_cmd.setdefault("api", self.api_name)
        self.api_cmd.setdefault('execute_mode', 'async')  # 默认在子线程中调用接口
        if hasattr(projectConfig, 'execute_mode'):
            mode = getattr(projectConfig, 'execute_mode')
            assert mode == 'main' or mode == 'async', 'execute_mode value must be "main" or "async"'
            self.api_cmd["execute_mode"] = mode
        if len(param) > 0:
            self.api_cmd.setdefault("param_name", list(param[0]))
            self.api_cmd.setdefault("param_type", list(param[1]))
            self.api_cmd.setdefault("param_value", list(param[2]))
        return str(self.api_cmd)

    def methods(self):
        return (list(filter(lambda m: not m.startswith("__") and not m.endswith("__") and callable(getattr(self, m)),
                            dir(self))))


class DemoApiBuilder(ApiBaseBuilder):
    api_name = "demoapi"

    @parameter(1, "int")
    def uid(self, uid):
        return self

    @parameter(2, "string")
    def mode(self, mode):
        return self


if __name__ == "__main__":
    # api = DemoApiBuilder().uid(1).mode("free").build()
    api = DemoApiBuilder().build()
    print(api)